package cn.mw.cmdb.service.impl;

import cn.mw.cmdb.constants.FinanceReportConstants;
import cn.mw.cmdb.entity.*;
import cn.mw.cmdb.entity.FinanceReport.*;
import cn.mw.cmdb.mongoMapper.FinanceReportHistoryInfoMapper;
import cn.mw.cmdb.mongoMapper.FinanceReportMappingRuleInfoMapper;
import cn.mw.cmdb.mongoMapper.InstanceReportResultInfoMapper;
import cn.mw.cmdb.param.*;
import cn.mw.cmdb.service.FinanceReportMappingRuleService;
import cn.mw.cmdb.util.AssetsTool;
import cn.mw.cmdb.util.BaseUtil;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.cmdb.util.GZIPUtils;
import cn.mw.cmdb.view.TreeViewObject;
import cn.mw.cmdb.view.ViewConvertContext;
import cn.mw.cmdb.view.ViewManager;
import cn.mw.components.mongodb.entity.*;
import cn.mw.components.mongodb.exception.BusinessException;
import cn.mw.components.mongodb.tool.CriteriaWrapper;
import cn.mw.log.client.LogClientSimple;
import cn.mw.log.enums.BusinessLogType;
import cn.mw.log.enums.LogLevel;
import cn.mw.microMonitorCommon.api.cmdb.TableIdEnum;
import cn.mw.microMonitorCommon.api.cmdb.TreeView;
import cn.mw.microMonitorCommon.api.common.FinanceReportChannelApiService;
import cn.mw.microMonitorCommon.entity.common.FinanceReportChannelDto;
import cn.mw.microMonitorCommon.enums.FinanceReportLogStatusEnum;
import cn.mw.microMonitorCommon.security.utils.AuthUtils;
import cn.mw.microMonitorCommon.security.utils.SecurityUtils;
import cn.mw.microMonitorCommon.util.DateUtils;
import cn.mw.microMonitorCommon.util.HttpUtils;
import cn.mw.microMonitorCommon.util.IDModelType;
import cn.mw.microMonitorCommon.util.ModuleIDManager;
import cn.mw.microMonitorCommon.utils.DatabaseUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

import static cn.mw.cmdb.util.ValConvertUtil.strValueConvert;

@Service
@Slf4j
public class FinanceReportMappingRuleServiceImpl extends BaseSearchService<FinanceReportMappingRuleInfo> implements FinanceReportMappingRuleService {

    @Autowired
    private FinanceReportMappingRuleInfoMapper financeReportMappingRuleInfoMapper;

    @Autowired
    private InstanceReportResultInfoMapper instanceReportResultInfoMapper;

    @Autowired
    private FinanceReportHistoryInfoMapper financeReportHistoryInfoMapper;

    @Autowired
    private ModuleIDManager moduleIDManager;

    @Autowired
    private ViewManager viewManager;

    @Autowired
    private LogClientSimple logClientSimple;

    @Autowired
    private MessageSource messageSource;

    @Autowired
    private CmdbServiceManage cmdbServiceManage;

    @Autowired
    private AuthUtils authUtils;

    @DubboReference(check = false, mock = "true" ,timeout = 15000)
    private FinanceReportChannelApiService financeReportChannelApiService;

    private static final String TOKEN_URL = "/webproxy/fig2fics/oauth2/v1/pshare/oauth/token";
    private static final String REPORT_URL = "/webproxy/fig2fics/pshare/api/prod/FICS/api/fics/dataElementInstance/reportData";
    private static final String QUERY_URL = "/webproxy/fig2fics/pshare/api/prod/FICS/api/fics/dataElementInstance/selectUploadData";

    @Override
    public Boolean addOrUpdateFinanceReportMappingRule(FinanceReportMappingRuleInfo financeReportMappingRuleInfo) throws Exception {

        if (CollectionUtils.isNotEmpty(financeReportMappingRuleInfo.getApplicationScopeList())) {
            List<String> modelGroupIdList = new ArrayList<>();
            List<String> modelIdList = new ArrayList<>();
            FinanceReportApplicationScopeVo financeReportApplicationScopeVo;
            for (List<FinanceReportApplicationScopeVo> financeReportApplicationScopeVoList : financeReportMappingRuleInfo.getApplicationScopeList()) {
                if (CollectionUtils.isNotEmpty(financeReportApplicationScopeVoList)) {
                    financeReportApplicationScopeVo = financeReportApplicationScopeVoList.get(financeReportApplicationScopeVoList.size() - 1);
                    if (TableIdEnum.model.equals(financeReportApplicationScopeVo.getType())) {
                        modelIdList.add(financeReportApplicationScopeVo.getId());
                    } else if (TableIdEnum.group.equals(financeReportApplicationScopeVo.getType())) {
                        modelGroupIdList.add(financeReportApplicationScopeVo.getId());
                    }
                }
            }

            // 查询应用范围内包含的所有模型 验证这些模型或者模型所属分组是否配置过映射规则
            List<ModelInfo> modelInfoList = getAllModelInfos(modelGroupIdList, modelIdList);
            List<String> applyModelGroupIdList;
            List<String> applyModelIdList;
            if (CollectionUtils.isEmpty(modelInfoList)) {
                applyModelGroupIdList = modelGroupIdList;
                applyModelIdList = modelIdList;
            } else {
                applyModelGroupIdList = modelInfoList.stream().flatMap(obj -> obj.getGroupPath().stream()).distinct().toList();
                applyModelIdList = modelInfoList.stream().map(ModelInfo::getId).toList();
            }

            List<Criteria> criteriaList = new ArrayList<>();
            Criteria criteria = CriteriaWrapper.where(FinanceReportMappingRuleInfo::getChannelIds).in(financeReportMappingRuleInfo.getChannelIds())
                    .orOperator(CriteriaWrapper.where(FinanceReportMappingRuleInfo::getModelGroupIdList).in(applyModelGroupIdList)
                            , CriteriaWrapper.where(FinanceReportMappingRuleInfo::getModelIdList).in(applyModelIdList));
            criteriaList.add(criteria);
            if (StringUtils.isNotBlank(financeReportMappingRuleInfo.getId())) {
                criteriaList.add(CriteriaWrapper.where(FinanceReportDictionaryInfo::getId).ne(financeReportMappingRuleInfo.getId()));
            }
            Query existQuery = new Query(new Criteria().andOperator(criteriaList));
            // 同一个上报通道 名称不能重复
            List<FinanceReportMappingRuleInfo> existInfos = financeReportMappingRuleInfoMapper.find(existQuery);
            if (CollectionUtils.isNotEmpty(existInfos)){
                throw new BusinessException("data-unique-error",new Object[]{existInfos.stream().map(FinanceReportMappingRuleInfo::getRuleName).toList().toString()});
            }

            financeReportMappingRuleInfo.setModelGroupIdList(modelGroupIdList);
            financeReportMappingRuleInfo.setModelIdList(modelIdList);
        }
        financeReportMappingRuleInfo.setLastUpdateDate(DateUtils.now());
        if (StringUtils.isBlank(financeReportMappingRuleInfo.getId())) {
            // 执行新增
            financeReportMappingRuleInfo.setCreateDate(DateUtils.now());
            financeReportMappingRuleInfo.setCreator(SecurityUtils.getUser().getNickName());
            financeReportMappingRuleInfo.setId(moduleIDManager.getIDStr(IDModelType.Model));
            financeReportMappingRuleInfoMapper.insert(financeReportMappingRuleInfo);
            logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                    messageSource.getMessage("log-add-finance-report-mapping-rule",null, LocaleContextHolder.getLocale()));
        } else {
            financeReportMappingRuleInfo.setLastUpdatedBy(SecurityUtils.getUser().getNickName());
            financeReportMappingRuleInfo.setLastUpdateDate(DateUtils.now());
            Query query  = new Query(CriteriaWrapper.where(DataSourceInfo::getId).is(financeReportMappingRuleInfo.getId()));
            Update update = CMDBTool.genMongoUpdate(financeReportMappingRuleInfo, null, null);
            CMDBTool.updateFirst(financeReportMappingRuleInfoMapper, query, update);
            logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                    messageSource.getMessage("log-update-finance-report-mapping-rule",null, LocaleContextHolder.getLocale()));
        }
        return true;
    }

    @Override
    public boolean batchDeleteFinanceReportMappingRule(List<String> ids) throws Exception {
        financeReportMappingRuleInfoMapper.remove(new Query(CriteriaWrapper.where(FinanceReportMappingRuleInfo::getId).in(ids)));
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("log-delete-finance-report-mapping-rule",null, LocaleContextHolder.getLocale()));
        return true;
    }

    @Override
    public Object getFinanceReportMappingRuleByPage(SearchParam param) throws Exception {
        Criteria criteria = genCriteria(param);
        // 设置引擎类型名称及引擎名称
        List<FinanceReportMappingRuleInfo> resultList = CMDBTool.selectPageList(financeReportMappingRuleInfoMapper, criteria, param);
        ViewConvertContext context = new ViewConvertContext();
        return viewManager.getListViewObject(resultList, FinanceReportMappingRuleInfo.class, param, context);
    }

    @Override
    public Object getApplicationScopeTree(List<Integer> channelIdList) throws Exception {
        // 查询上报通道配置的所有分组、模型ID
        Criteria criteria = CriteriaWrapper.where(FinanceReportMappingRuleInfo::getChannelIds).in(channelIdList);
        // 设置引擎类型名称及引擎名称
        List<FinanceReportMappingRuleInfo> resultList = CMDBTool.selectPageList(financeReportMappingRuleInfoMapper, criteria, new TableSearchParam());
        List<String> modelGroupIdList = new ArrayList<>(resultList.stream().flatMap(obj -> obj.getModelGroupIdList().stream()).distinct().toList());
        List<String> modelIds = resultList.stream().flatMap(obj -> obj.getModelIdList().stream()).distinct().toList();

        // 剔除已经设置规则的模型
        CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        ModelSearchParam modelSearchParam = new ModelSearchParam();
        modelSearchParam.addSubCondition(CMDBTool.getFieldName(ModelInfo::getId)
                , new SubCondition(CriteriaOpsType.nin.name(), modelIds));
        modelSearchParam.addSubCondition(CMDBTool.getFieldName(ModelInfo::getFunctionModule)
                , new SubCondition(CriteriaOpsType.in.name(), FunctionModuleEnum.financeReport.getCode()));
        List<ModelInfo> modelInfos = modelService.doSelectShowNormalModelByPath(modelSearchParam);
        List<TreeView> list = new ArrayList<>(modelInfos);

        // 剔除已经配置了规则的分组
        ModelGroupServiceImpl modelGroupService = (ModelGroupServiceImpl) cmdbServiceManage.getModelService(ModelGroupServiceImpl.ID);
        GroupSearchParam searchParam = new GroupSearchParam();
        searchParam.setOperation(CriteriaOpsType.and.name());
        searchParam.setSearchClass(ModelGroupInfo.class);
        Map<String, SubCondition> groupIdCondition = new HashMap<>();
        groupIdCondition.put(CMDBTool.getFieldName(ModelGroupInfo::getId), new SubCondition(CriteriaOpsType.nin.name(), modelGroupIdList));
        searchParam.setCondition(groupIdCondition);
        list.addAll(modelGroupService.getShowModelGroupList(searchParam));

        ViewConvertContext context = new ViewConvertContext();
        context.setSelectDropType(TableIdEnum.model.getCode());
        return viewManager.getTreeViewObject(list, context);
    }

    @Override
    public Object getReportTree(Integer channelId) throws Exception {
        // 查询上报通道配置的所有分组、模型ID
        Criteria criteria = CriteriaWrapper.where(FinanceReportMappingRuleInfo::getChannelIds).in(Arrays.asList(channelId));
        // 设置引擎类型名称及引擎名称
        List<FinanceReportMappingRuleInfo> resultList = CMDBTool.selectPageList(financeReportMappingRuleInfoMapper, criteria, new TableSearchParam());
        List<String> modelGroupIdList = new ArrayList<>(resultList.stream().flatMap(obj -> obj.getModelGroupIdList().stream()).distinct().toList());
        List<String> modelIdList = new ArrayList<>(resultList.stream().flatMap(obj -> obj.getModelIdList().stream()).distinct().toList());

        List<TreeView> list = new ArrayList<>();
        List<ModelInfo> modelInfos = getAllModelInfos(null, modelIdList);
        if (CollectionUtils.isNotEmpty(modelInfos)) {
            modelInfos.forEach(item -> {
                modelGroupIdList.addAll(item.getGroupPath());
            });
        }
        modelInfos = getAllModelInfos(modelGroupIdList, null);
        if (CollectionUtils.isNotEmpty(modelInfos)) {
            list.addAll(modelInfos);
        }

        InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
        InstanceSearchParam param = new InstanceSearchParam();
        param.setModelIds(modelInfos.stream().map(ModelInfo::getId).toList());
        param.addSubCondition(CMDBTool.getFieldName(ModelInfo::getFunctionModule)
                , new SubCondition(CriteriaOpsType.in.name(), FunctionModuleEnum.financeReport.getCode()));
        List<InstanceGroupByPathAndStatus> groupRet = instanceService.groupCountByPathAndStatus(param);
        Set<String> groupSet = new HashSet<>();
        Map<String, List<AssetsTool.ItemAssetsStatusContext>> idContextMap = AssetsTool.initModelAndGroupIdSet(new HashSet<>(), groupSet, groupRet);

        ModelGroupServiceImpl modelGroupService = (ModelGroupServiceImpl) cmdbServiceManage.getModelService(ModelGroupServiceImpl.ID);
        GroupSearchParam searchParam = new GroupSearchParam();
        Map<String, SubCondition> groupPathCondition = new HashMap<>();
        groupPathCondition.put(CMDBTool.getFieldName(ModelGroupInfo::getId), new SubCondition(CriteriaOpsType.in.name(), new ArrayList<>(groupSet)));
        searchParam.setCondition(groupPathCondition);
        searchParam.setOperation(CriteriaOpsType.and.name());
        searchParam.setSearchClass(ModelGroupInfo.class);
        list.addAll(modelGroupService.getShowModelGroupList(searchParam));

        ViewConvertContext context = new ViewConvertContext();
        context.setSelectDropType(TableIdEnum.model.getCode());
        for (TreeView treeView : list) {
            String id = strValueConvert(treeView.getId());
            List<AssetsTool.ItemAssetsStatusContext> contexts = idContextMap.get(id);
            if (null != contexts) {
                treeView.setCount(AssetsTool.calcItemAssetsStatusCount(contexts));
            }
        }
        List<TreeViewObject> treeViewObjectList = (List<TreeViewObject>) viewManager.getTreeViewObject(list, context);
        // 移除没有模型的中间结点
        removeEmptyGroup(treeViewObjectList);
        return treeViewObjectList;
    }

    private void removeEmptyGroup(Object params) {
        if (params != null) {
            List<TreeViewObject> treeViewObjectList = (List<TreeViewObject>) params;
            Iterator<TreeViewObject> iterator = treeViewObjectList.iterator();
            while (iterator.hasNext()) {
                TreeViewObject treeViewObject = iterator.next();
                if (!TableIdEnum.model.getCode().equals(treeViewObject.getType()) && !isHasModelNode(treeViewObject.getChilds())) {
                    iterator.remove();
                }
                removeEmptyGroup(treeViewObject.getChilds());
            }
        }
    }

    private boolean isHasModelNode(Object childNodes) {
        if (childNodes == null) {
            return false;
        }
        List<TreeViewObject> treeViewObjectList = (List<TreeViewObject>) childNodes;
        for (TreeViewObject treeViewObject : treeViewObjectList) {
            if (TableIdEnum.model.getCode().equals(treeViewObject.getType())) {
                return true;
            }
            if (isHasModelNode(treeViewObject.getChilds())) {
                return true;
            }
        }
        return false;
    }

    @Override
    public FinanceReportCheckResultVo reportCheck(Integer channelId, List<String> instanceIdList, String batchId) throws Exception {
        // 获取所选范围所有模型
        InstanceSearchParam instanceSearchParam = new InstanceSearchParam();
        instanceSearchParam.setInstanceIds(instanceIdList);
        InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
        List<InstanceInfoExtend> instanceInfoList = instanceService.aggregateList(instanceSearchParam);
        List<String> modelIdList = instanceInfoList.stream().map(InstanceInfo::getModelId).toList();
        List<String> existsInstanceIDList = instanceInfoList.stream().map(InstanceInfo::getModelId).toList();
        List<String> modelGroupIdList = instanceInfoList.stream().flatMap(item -> item.getPath().stream()).distinct().toList();

        // 查询所有匹配的映射规则
        List<Criteria> criteriaList = new ArrayList<>();
        Criteria criteria = CriteriaWrapper.where(FinanceReportMappingRuleInfo::getChannelIds).in(channelId)
                .orOperator(CriteriaWrapper.where(FinanceReportMappingRuleInfo::getModelGroupIdList).in(modelGroupIdList)
                        , CriteriaWrapper.where(FinanceReportMappingRuleInfo::getModelIdList).in(modelIdList));
        criteriaList.add(criteria);
        Query existQuery = new Query(new Criteria().andOperator(criteriaList));
        List<FinanceReportMappingRuleInfo> mappingRuleInfos = financeReportMappingRuleInfoMapper.find(existQuery);

        // 按照模型维度 获取对应的映射规则
        FinanceReportMappingRuleInfo financeReportMappingRuleInfo;
        FinanceReportCheckResultVo financeReportCheckResultVo = new FinanceReportCheckResultVo();
        financeReportCheckResultVo.setBatchId(batchId);
        List<InstanceReportCheckInfo> reportCheckInfoList = new ArrayList<>();
        financeReportCheckResultVo.setCheckInfoList(reportCheckInfoList);

        // 实例按照模型分组
        Map<String, List<InstanceInfoExtend>> modelId2InstanceList = instanceInfoList.stream().collect(Collectors.groupingBy(InstanceInfoExtend::getModelId));

        for (Map.Entry<String, List<InstanceInfoExtend>> entry : modelId2InstanceList.entrySet()) {
            financeReportMappingRuleInfo = getMappingRuleByModel(mappingRuleInfos, entry.getValue().get(0).getModelId(), entry.getValue().get(0).getGroupId());
            // 查询出模型下所有实例 按照映射规则转换成对象
            reportCheckInfoList.addAll(parseParamsByInstanceList(entry.getValue(), financeReportMappingRuleInfo, channelId));
        }

        dealDeleteInstance(instanceIdList, existsInstanceIDList, reportCheckInfoList);

        int successCount = reportCheckInfoList.stream().filter(InstanceReportCheckInfo::getCheckResult).toList().size();
        int failedCount = reportCheckInfoList.stream().filter(item -> !item.getCheckResult()).toList().size();
        financeReportCheckResultVo.setSuccessCount(successCount);
        financeReportCheckResultVo.setFailedCount(failedCount);
        return financeReportCheckResultVo;
    }

    private void dealDeleteInstance(List<String> instanceIdList, List<String> existsInstanceIDList, List<InstanceReportCheckInfo> reportCheckInfoList) throws Exception {
        // 未查询到的实例表示已经删除 需要上报进行删除
        List<String> deleteInstances = new ArrayList<>();
        for (String instanceId : instanceIdList) {
            if (!existsInstanceIDList.contains(instanceId)) {
                deleteInstances.add(instanceId);
            }
        }
        if (CollectionUtils.isNotEmpty(deleteInstances)) {
            List<Criteria> criteriaList = new ArrayList<>();
            // 查询上报历史 获取上一次上报成功的数据
            Criteria criteria = CriteriaWrapper.where(InstanceReportResultInfo::getInstanceId).in(instanceIdList)
                    .andOperator(CriteriaWrapper.where(InstanceReportResultInfo::getReportResult).is(FinanceReportConstants.QueryStatus.SAVE_SUCCESS));
            criteriaList.add(criteria);
            Query existQuery = new Query(new Criteria().andOperator(criteriaList));
            List<InstanceReportResultInfo> instanceReportResultInfoList = instanceReportResultInfoMapper.find(existQuery);
            instanceReportResultInfoList.forEach(item -> {
                InstanceReportCheckInfo instanceReportCheckInfo = new InstanceReportCheckInfo();
                instanceReportCheckInfo.setInstanceId(item.getInstanceId());
                instanceReportCheckInfo.setInstanceName(item.getInstanceName());
                instanceReportCheckInfo.setModelGroupName(item.getModelGroupName());
                instanceReportCheckInfo.setModelName(item.getModelName());
                instanceReportCheckInfo.setFacilityDescriptor(item.getFacilityDescriptor());
                instanceReportCheckInfo.setFacilityCategory(item.getFacilityCategory());
                instanceReportCheckInfo.setRequestParam(item.getRequestParam());
                instanceReportCheckInfo.setCheckResult(true);
                instanceReportCheckInfo.setReportDataType(FinanceReportConstants.ReportDataType.DELETE);
                instanceReportCheckInfo.getRequestParam().put(DatabaseUtils.getFieldName(InstanceReportCheckInfo::getReportDataType), instanceReportCheckInfo.getReportDataType());
                reportCheckInfoList.add(instanceReportCheckInfo);
            });
        }
    }

    @Override
    public Object doReport(FinanceReportCheckResultVo financeReportCheckResultVo) throws Exception {
        // 获取所有校验通过的数据 组装参数调用金融元上报接口
        List<InstanceReportCheckInfo> reportCheckInfoList = financeReportCheckResultVo.getCheckInfoList();

        if (CollectionUtils.isNotEmpty(reportCheckInfoList)) {
            Integer channelId = reportCheckInfoList.get(0).getChannelId();
            FinanceReportChannelDto financeReportChannelDto = financeReportChannelApiService.getFinanceReportChannelById(channelId);

            // 生成上报历史
            FinanceReportHistoryInfo financeReportHistoryInfo = new FinanceReportHistoryInfo();
            financeReportHistoryInfo.setId(moduleIDManager.getIDStr(IDModelType.Model));
            financeReportHistoryInfo.setReportDate(DateUtils.now());
            financeReportHistoryInfo.setCurrentCode(FinanceReportConstants.ReportStatus.SAVE_SUCCESS);
            financeReportHistoryInfo.setReportStatus(FinanceReportLogStatusEnum.doing.getDesc());
            financeReportHistoryInfo.setChannel(channelId);
            financeReportHistoryInfo.setFacilityOwnerAgency(financeReportChannelDto.getFacilityOwnerAgency());
            financeReportHistoryInfo.setReportBy(SecurityUtils.getUser().getNickName());
            financeReportHistoryInfo.setInstanceIDList(reportCheckInfoList.stream().map(InstanceReportCheckInfo::getInstanceId).toList());

            if (financeReportChannelDto != null) {
                FinanceReportRequestParam reportRequestParam = new FinanceReportRequestParam();
                if (StringUtils.isNotEmpty(financeReportCheckResultVo.getBatchId())) {
                    reportRequestParam.setBranchId(financeReportCheckResultVo.getBatchId());
                }
                reportRequestParam.setFacilityOwnerAgency(financeReportChannelDto.getFacilityOwnerAgency());
                List<FinanceReportRequestDataParam> data = new ArrayList<>();
                FinanceReportRequestDataParam financeReportRequestDataParam;
                Map<String, List<InstanceReportCheckInfo>> modelName2CheckInfoListMap = reportCheckInfoList.stream().filter(InstanceReportCheckInfo::getCheckResult).collect(Collectors.groupingBy(InstanceReportCheckInfo::getModelName));
                for (Map.Entry<String, List<InstanceReportCheckInfo>> entry : modelName2CheckInfoListMap.entrySet()) {
                    financeReportRequestDataParam = new FinanceReportRequestDataParam();
                    financeReportRequestDataParam.setDataType(entry.getKey());
                    financeReportRequestDataParam.setDataList(entry.getValue().stream().map(InstanceReportCheckInfo::getRequestParam).toList());
                    data.add(financeReportRequestDataParam);
                }
                reportRequestParam.setData(data);

                String accessToken = getAccessToken(financeReportChannelDto);
                String reportUrl = String.format(Locale.ENGLISH, "%s%s", financeReportChannelDto.getServerUrl(), REPORT_URL);
                // 对请求参数进行压缩
                String compressedBody = GZIPUtils.compress(JSON.toJSONString(reportRequestParam));
                Map<String, String> headers = new HashMap<>();
                headers.put("Content-Type", "application/json");
                headers.put("connection", "Keep-Alive");
                headers.put("Charset", "UTF-8");
                headers.put("Content-Length", String.valueOf(compressedBody.length()));
                headers.put("X-Access-Token", accessToken);

                String response = HttpUtils.sendPostRequest(reportUrl, compressedBody, headers);
                if (StringUtils.isNotBlank(response)) {
                    log.info("finance report result:{}", response);
                    FinanceReportResponseVo financeReportResponseVo = JSON.parseObject(response, FinanceReportResponseVo.class);
                    financeReportHistoryInfo.setBranchId(financeReportResponseVo.getBranchId());
                    financeReportHistoryInfo.setCurrentCode(financeReportResponseVo.getCode());
                    if (!StringUtils.equals(financeReportResponseVo.getCode(), FinanceReportConstants.ReportStatus.SAVE_SUCCESS)) {
                        financeReportHistoryInfo.setReportStatus(FinanceReportLogStatusEnum.failed.getCode());
                    }
                    financeReportHistoryInfo.setMsg(financeReportResponseVo.getMsg());
                    financeReportHistoryInfoMapper.insert(financeReportHistoryInfo);
                    saveInstanceReportHis(reportCheckInfoList, financeReportResponseVo, financeReportHistoryInfo);
                    return StringUtils.equals(financeReportResponseVo.getCode(), FinanceReportConstants.ReportStatus.SAVE_SUCCESS);
                } else {
                    log.info("finance report error:{}", JSON.toJSONString(response));
                }
            }
        }
        return false;
    }

    @Override
    public Object queryReportResult(String historyId) throws Exception {
        // 查询上报任务
        FinanceReportHistoryInfo financeReportHistoryInfo = financeReportHistoryInfoMapper.findOne(new Query(CriteriaWrapper.where(FinanceReportHistoryInfo::getId).is(historyId)));
        FinanceReportChannelDto financeReportChannelDto = financeReportChannelApiService.getFinanceReportChannelById(financeReportHistoryInfo.getChannel());
        if (financeReportChannelDto != null) {
            String accessToken = getAccessToken(financeReportChannelDto);
            FinanceReportRequestParam financeReportRequestParam = new FinanceReportRequestParam();
            financeReportRequestParam.setBranchId(financeReportHistoryInfo.getBranchId());
            financeReportRequestParam.setFacilityOwnerAgency(financeReportChannelDto.getFacilityOwnerAgency());
            String reportUrl = String.format(Locale.ENGLISH, "%s%s", financeReportChannelDto.getServerUrl(), QUERY_URL);
            Map<String, String> headers = new HashMap<>();
            headers.put("connection", "Keep-Alive");
            headers.put("Charset", "UTF-8");
            headers.put("Content-Type", "application/json");
            headers.put("X-Access-Token", accessToken);
            String response = HttpUtils.sendPostRequest(reportUrl, JSON.toJSONString(financeReportRequestParam), headers);
            if (StringUtils.isNotBlank(response)) {
                log.info("queryReportResult response:{}", response);
                FinanceReportResponseVo financeReportResponseVo = JSON.parseObject(response, FinanceReportResponseVo.class);
                // 处理成功的数据更新实例上报结果
                if (StringUtils.equals(financeReportResponseVo.getCode(), FinanceReportConstants.QueryStatus.SAVE_SUCCESS)) {
                    Query hisQuery = new Query(CriteriaWrapper.where(FinanceReportHistoryInfo::getId).is(historyId));
                    //根据map字段产生更新信息
                    Update hisUpdate = new Update();
                    hisUpdate.set(DatabaseUtils.getFieldName(FinanceReportHistoryInfo::getCurrentCode), financeReportResponseVo.getCode());
                    hisUpdate.set(DatabaseUtils.getFieldName(FinanceReportHistoryInfo::getMsg), financeReportResponseVo.getMsg());
                    hisUpdate.set(DatabaseUtils.getFieldName(FinanceReportHistoryInfo::getReportStatus), getReportStatus(financeReportResponseVo.getCode()));
                    hisUpdate.set(DatabaseUtils.getFieldName(FinanceReportHistoryInfo::getReportCompleteDate), DateUtils.now());
                    financeReportHistoryInfoMapper.updateMulti(hisQuery, hisUpdate);

                    updateInstanceReportResult(financeReportResponseVo, historyId);
                }
            }
        }
        return instanceReportResultInfoMapper.find(new Query(CriteriaWrapper.where(InstanceReportResultInfo::getHistoryId).is(historyId)));
    }

    private String getReportStatus(String reportCode) {
        if (StringUtils.isBlank(reportCode)) {
            return FinanceReportLogStatusEnum.doing.getDesc();
        }
        switch (reportCode) {
            case FinanceReportConstants.ReportStatus.SAVE_SUCCESS:
            case FinanceReportConstants.QueryStatus.DOING:
                return FinanceReportLogStatusEnum.doing.getDesc();
            case FinanceReportConstants.QueryStatus.SAVE_SUCCESS:
            case FinanceReportConstants.QueryStatus.PROCESS_SUCCESS:
                return FinanceReportLogStatusEnum.completed.getDesc();
            case FinanceReportConstants.QueryStatus.PARTIAL_SUCCESS:
                return FinanceReportLogStatusEnum.partCompleted.getDesc();
            default:
                return FinanceReportLogStatusEnum.failed.getDesc();
        }
    }

    private void updateInstanceReportResult(FinanceReportResponseVo financeReportResponseVo, String historyId) throws Exception {
        // 已保存标识所有数据都上报成功
        switch (financeReportResponseVo.getCode()) {
            case FinanceReportConstants.QueryStatus.DOING:
                break;
            case FinanceReportConstants.QueryStatus.PROCESS_SUCCESS:
            case FinanceReportConstants.QueryStatus.SAVE_SUCCESS: {
                Query query = new Query(CriteriaWrapper.where(InstanceReportResultInfo::getHistoryId).is(historyId).andOperator(CriteriaWrapper.where(InstanceReportResultInfo::getCheckResult).is(true)));
                //根据map字段产生更新信息
                Update update = new Update();
                update.set(DatabaseUtils.getFieldName(InstanceReportResultInfo::getCurrentCode), financeReportResponseVo.getCode());
                update.set(DatabaseUtils.getFieldName(InstanceReportResultInfo::getReportResult), true);
                update.set(DatabaseUtils.getFieldName(InstanceReportResultInfo::getMessage), financeReportResponseVo.getMsg());
                instanceReportResultInfoMapper.updateMulti(query, update);
                break;
            }
            case FinanceReportConstants.QueryStatus.PARTIAL_SUCCESS:
            case FinanceReportConstants.QueryStatus.FAILED:
                // 查询该批次上报的所有实例信息
                List<InstanceReportResultInfo> instanceReportResultInfoList = instanceReportResultInfoMapper.find(new Query(CriteriaWrapper.where(InstanceReportResultInfo::getHistoryId).is(historyId)
                        .andOperator(CriteriaWrapper.where(InstanceReportResultInfo::getCheckResult).is(true))));
                List<String> successList = new ArrayList<>();
                List<FinanceReportResponseDataVo> financeReportResponseDataVoList = financeReportResponseVo.getData();
                Map<String, List<String>> msg2FacilityDescriptorMap = new HashMap<>();
                Map<String, String> code2Msg = new HashMap<>();
                for (FinanceReportResponseDataVo financeReportResponseDataVo : financeReportResponseDataVoList) {
                    if (!msg2FacilityDescriptorMap.containsKey(financeReportResponseDataVo.getFacilityDescriptor())) {
                        msg2FacilityDescriptorMap.put(financeReportResponseDataVo.getFacilityDescriptor(), new ArrayList<>());
                        code2Msg.put(financeReportResponseDataVo.getCode(), financeReportResponseDataVo.getMsg());
                    }
                    msg2FacilityDescriptorMap.get(financeReportResponseDataVo.getFacilityDescriptor()).add(financeReportResponseDataVo.getFacilityDescriptor());
                }

                List<String> failedList = financeReportResponseDataVoList.stream().map(FinanceReportResponseDataVo::getFacilityDescriptor).toList();
                instanceReportResultInfoList.forEach(item -> {
                    if (!failedList.contains(item.getFacilityDescriptor())) {
                        successList.add(item.getFacilityDescriptor());
                    }
                });

                // 更新成功的数量
                Query successQuery = new Query(CriteriaWrapper.where(InstanceReportResultInfo::getHistoryId).is(historyId).andOperator(CriteriaWrapper.where(InstanceReportResultInfo::getFacilityDescriptor).in(successList)));
                Update successUpdate = new Update();
                successUpdate.set(DatabaseUtils.getFieldName(InstanceReportResultInfo::getCurrentCode), FinanceReportConstants.QueryStatus.PROCESS_SUCCESS);
                successUpdate.set(DatabaseUtils.getFieldName(InstanceReportResultInfo::getReportResult), true);
                instanceReportResultInfoMapper.updateMulti(successQuery, successUpdate);

                // 更新失败的数量
                for (Map.Entry<String, List<String>> entry : msg2FacilityDescriptorMap.entrySet()) {
                    // 更新成功的数量
                    Query failedQuery = new Query(CriteriaWrapper.where(InstanceReportResultInfo::getHistoryId).is(historyId).andOperator(CriteriaWrapper.where(InstanceReportResultInfo::getFacilityDescriptor).in(entry.getValue())));
                    Update failedUpdate = new Update();
                    failedUpdate.set(DatabaseUtils.getFieldName(InstanceReportResultInfo::getCurrentCode), entry.getKey());
                    failedUpdate.set(DatabaseUtils.getFieldName(InstanceReportResultInfo::getMessage), code2Msg.get(entry.getKey()));
                    successUpdate.set(DatabaseUtils.getFieldName(InstanceReportResultInfo::getReportResult), false);
                    instanceReportResultInfoMapper.updateMulti(failedQuery, failedUpdate);
                }
                break;
            default:
                break;
        }
    }

    @Override
    public FinanceReportCheckResultVo reDoReport(String historyId) throws Exception {
        FinanceReportHistoryInfo financeReportHistoryInfo = financeReportHistoryInfoMapper.findOne(new Query(CriteriaWrapper.where(FinanceReportHistoryInfo::getId).is(historyId)));
        if (financeReportHistoryInfo == null) {
            return null;
        }
        return reportCheck(financeReportHistoryInfo.getChannel(), financeReportHistoryInfo.getInstanceIDList(), financeReportHistoryInfo.getBranchId());
    }

    private void saveInstanceReportHis(List<InstanceReportCheckInfo> reportCheckInfoList, FinanceReportResponseVo financeReportResponseVo, FinanceReportHistoryInfo financeReportHistoryInfo) {
        List<InstanceReportResultInfo> instanceReportResultInfos = new ArrayList<>();
        String userName = SecurityUtils.getUser().getNickName();
        reportCheckInfoList.forEach(item -> {
            InstanceReportResultInfo instanceReportResultInfo = new InstanceReportResultInfo();
            instanceReportResultInfo.setInstanceId(item.getInstanceId());
            instanceReportResultInfo.setModelName(item.getModelName());
            instanceReportResultInfo.setModelGroupName(item.getModelGroupName());
            instanceReportResultInfo.setInstanceName(item.getInstanceName());
            instanceReportResultInfo.setChannelId(item.getChannelId());
            instanceReportResultInfo.setHistoryId(financeReportHistoryInfo.getId());
            instanceReportResultInfo.setFacilityCategory(item.getFacilityCategory());
            instanceReportResultInfo.setFacilityDescriptor(item.getFacilityDescriptor());
            instanceReportResultInfo.setReportResult(false);
            if (item.getCheckResult()) {
                instanceReportResultInfo.setCurrentCode(financeReportResponseVo.getCode());
                instanceReportResultInfo.setMessage(financeReportResponseVo.getMsg());
            } else {
                instanceReportResultInfo.setCurrentCode(FinanceReportConstants.ReportStatus.DATA_ERROR);
            }
            instanceReportResultInfo.setReporter(userName);
            instanceReportResultInfo.setRequestParam(item.getRequestParam());
            instanceReportResultInfo.setReportDate(BaseUtil.getNowLocalTime());
            instanceReportResultInfo.setCheckResult(item.getCheckResult());
            instanceReportResultInfo.setCheckMessage(item.getCheckMessage());
            instanceReportResultInfos.add(instanceReportResultInfo);
        });
        instanceReportResultInfoMapper.insertAll(instanceReportResultInfos);
    }

    @Override
    public boolean batchDeleteFinanceReportHistory(List<String> ids) throws Exception {
        financeReportHistoryInfoMapper.remove(new Query(CriteriaWrapper.where(FinanceReportMappingRuleInfo::getId).in(ids)));
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("log-delete-finance-report-history", null, LocaleContextHolder.getLocale()));
        return true;
    }

    @Override
    public Map<String, Integer> getFinanceReportHistoryStatusCount(SearchParam param) throws Exception {
        param.setSearchClass(FinanceReportHistoryInfo.class);
        Criteria criteria = genCriteria(param);
        param.setPage(null);
        GroupSearchOperation groupSearchOperation = new GroupSearchOperation();
        String groupName = CMDBTool.getFieldName(FinanceReportHistoryInfo::getReportStatus);
        groupSearchOperation.addGroupField(CMDBTool.getFieldName(FinanceReportHistoryStatusCountInfo::getReportStatus), groupName);
        groupSearchOperation.addCalculateField(CMDBTool.getFieldName(FinanceReportHistoryStatusCountInfo::getCount), GroupCalculateMethodEnum.count, groupName);
        param.setGroupSearchOperation(groupSearchOperation);
        List<FinanceReportHistoryStatusCountInfo> result = CMDBTool.aggregateAuthorizedList(FinanceReportHistoryStatusCountInfo.class, financeReportHistoryInfoMapper, criteria, param);
        Map<String, Integer> status2CountMap = new LinkedHashMap<>();
        status2CountMap.put(FinanceReportLogStatusEnum.completed.getDesc(), 0);
        status2CountMap.put(FinanceReportLogStatusEnum.partCompleted.getDesc(), 0);
        status2CountMap.put(FinanceReportLogStatusEnum.doing.getDesc(), 0);
        status2CountMap.put(FinanceReportLogStatusEnum.failed.getDesc(), 0);
        if (CollectionUtils.isNotEmpty(result)) {
            Map<String, Integer> queryMap = result.stream().collect(Collectors.toMap(FinanceReportHistoryStatusCountInfo::getId, FinanceReportHistoryStatusCountInfo::getCount));
            for (Map.Entry<String, Integer> item : queryMap.entrySet()) {
                if (status2CountMap.containsKey(item.getKey())) {
                    status2CountMap.put(item.getKey(), status2CountMap.get(item.getKey()) + item.getValue());
                } else {
                    status2CountMap.put(item.getKey(), item.getValue());
                }
            }
        }
        return status2CountMap;
    }

    private String getAccessToken(FinanceReportChannelDto financeReportChannelDto) {
        String serverUrl = String.format(Locale.ENGLISH, "%s%s", financeReportChannelDto.getServerUrl(), TOKEN_URL);
        String userName = financeReportChannelDto.getUserName();
        String authToken = financeReportChannelDto.getAuthToken();
        Map<String, String> requestParam = new HashMap<>();
        requestParam.put("grant_type", "client_credentials");
        requestParam.put("client_id", userName);
        requestParam.put("client_secret", authToken);
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        String response = HttpUtils.sendPostRequest(serverUrl, JSON.toJSONString(requestParam), headers);
        if (StringUtils.isNotBlank(response)) {
            log.info("get access token result:{}", response);
            Map resultMap = JSON.parseObject(response, Map.class);
            return (String) resultMap.get("access_token");
        } else {
            log.error("get access token error! params:{}", JSON.toJSONString(requestParam));
        }
        return null;
    }

    private List<InstanceReportCheckInfo> parseParamsByInstanceList(List<InstanceInfoExtend> instanceInfoList, FinanceReportMappingRuleInfo financeReportMappingRuleInfo, Integer channelId) throws Exception {
        List<InstanceReportCheckInfo> reportCheckInfoList = new ArrayList<>();
        InstanceReportCheckInfo instanceReportCheckInfo;
        for (InstanceInfoExtend instanceInfo : instanceInfoList) {
            instanceReportCheckInfo = new InstanceReportCheckInfo();
            instanceReportCheckInfo.setInstanceId(instanceInfo.getId());
            instanceReportCheckInfo.setInstanceName(instanceInfo.getInstanceName());
            instanceReportCheckInfo.setModelName(instanceInfo.getModelName());
            instanceReportCheckInfo.setModelGroupName(instanceInfo.getModelGroupName());
            instanceReportCheckInfo.setChannelId(channelId);
            if (financeReportMappingRuleInfo == null) {
                instanceReportCheckInfo.setCheckResult(false);
                instanceReportCheckInfo.setCheckMessage(messageSource.getMessage("finance-report-instance-have-no-mapping-rule", new Object[]{instanceInfo.getInstanceName()}, LocaleContextHolder.getLocale()));
            } else {
                checkParams(instanceReportCheckInfo, instanceInfo, financeReportMappingRuleInfo);
            }
            reportCheckInfoList.add(instanceReportCheckInfo);
        }

        // 查询设备上报历史 设置上报类型
        List<String> facilityDescriptor = reportCheckInfoList.stream().map(InstanceReportCheckInfo::getFacilityDescriptor).filter(Objects::nonNull).toList();
        if (CollectionUtils.isNotEmpty(facilityDescriptor)) {
            List<Criteria> criteriaList = new ArrayList<>();
            Criteria criteria = CriteriaWrapper.where(InstanceReportResultInfo::getFacilityDescriptor).in(facilityDescriptor)
                    .andOperator(CriteriaWrapper.where(InstanceReportResultInfo::getCheckResult).is(true));
            criteriaList.add(criteria);
            Query existQuery = new Query(new Criteria().andOperator(criteriaList));
            List<InstanceReportResultInfo> instanceReportResultInfoList = instanceReportResultInfoMapper.find(existQuery);
            Map<String, List<InstanceReportResultInfo>> descriptor2InstanceList = instanceReportResultInfoList.stream().collect(Collectors.groupingBy(InstanceReportResultInfo::getFacilityDescriptor));
            reportCheckInfoList.forEach(item -> {
                if (item.getCheckResult()) {
                    if (descriptor2InstanceList.containsKey(item.getFacilityDescriptor())) {
                        setReportDataTypeByReportHis(item, descriptor2InstanceList.get(item.getFacilityDescriptor()));
                    } else {
                        // 第一次上报 设置上报类型为新增
                        item.setReportDataType(FinanceReportConstants.ReportDataType.NEW);
                    }
                    item.getRequestParam().put(DatabaseUtils.getFieldName(InstanceReportCheckInfo::getReportDataType), item.getReportDataType());
                }
            });
        }
        return reportCheckInfoList;
    }

    private void setReportDataTypeByReportHis(InstanceReportCheckInfo reportCheckInfo, List<InstanceReportResultInfo> reportResultInfos) {
        // 按照上报时间排序 获取最后一次上报结果状态
        String lastReportCode = reportResultInfos.stream().sorted(Comparator.comparing(InstanceReportResultInfo::getReportDate).reversed()).toList().get(0).getCurrentCode();
        if (StringUtils.equals(FinanceReportConstants.ReportStatus.SAVE_SUCCESS, lastReportCode) || StringUtils.equals(FinanceReportConstants.QueryStatus.DOING, lastReportCode)) {
            reportCheckInfo.setCheckResult(false);
            reportCheckInfo.setCheckMessage(messageSource.getMessage("finance-report-instance-is-reporting", null, LocaleContextHolder.getLocale()));
        } else if (StringUtils.equals(FinanceReportConstants.QueryStatus.SAVE_SUCCESS, lastReportCode) || StringUtils.equals(FinanceReportConstants.QueryStatus.PROCESS_SUCCESS, lastReportCode)) {
            reportCheckInfo.setReportDataType(FinanceReportConstants.ReportDataType.UPDATE);
        } else {
            reportCheckInfo.setReportDataType(FinanceReportConstants.ReportDataType.NEW);
        }
    }

    private void checkParams(InstanceReportCheckInfo instanceReportCheckInfo, InstanceInfoExtend instanceInfo, FinanceReportMappingRuleInfo financeReportMappingRuleInfo) throws Exception {
        Map<String, Object> requestParam = new HashMap<>();
        List<FinanceReportPropertyMappingVo> propertyMappingList = financeReportMappingRuleInfo.getPropertyMappingList();
        PropertyInfo sourceProperty;
        FinanceReportDictionaryInfo targetProperty;
        Object sourceValue;
        for (FinanceReportPropertyMappingVo financeReportPropertyMappingVo : propertyMappingList) {
            sourceProperty = financeReportPropertyMappingVo.getSourceProperty();
            sourceValue = getSourceValue(sourceProperty, instanceInfo);
            targetProperty = financeReportPropertyMappingVo.getTargetProperty();
            // 根据目标字段的约束条件对源字段进行校验
            if (checkByTargetConstraint(sourceValue, targetProperty, instanceReportCheckInfo)) {
                requestParam.put(targetProperty.getFacilityName(), sourceValue);
            } else {
                return;
            }
        }
        // 分类标识符与设备标识符校验
        if (!requestParam.containsKey(DatabaseUtils.getFieldName(FinanceReportResponseDataVo::getFacilityCategory))
                || requestParam.get(DatabaseUtils.getFieldName(FinanceReportResponseDataVo::getFacilityCategory)) == null) {
            instanceReportCheckInfo.setCheckResult(false);
            instanceReportCheckInfo.setCheckMessage(messageSource.getMessage("finance-report-facility-category-is-null", null, LocaleContextHolder.getLocale()));
            return;
        }
        if (!requestParam.containsKey(DatabaseUtils.getFieldName(FinanceReportResponseDataVo::getFacilityDescriptor))
                || requestParam.get(DatabaseUtils.getFieldName(FinanceReportResponseDataVo::getFacilityDescriptor)) == null) {
            instanceReportCheckInfo.setCheckResult(false);
            instanceReportCheckInfo.setCheckMessage(messageSource.getMessage("finance-report-facility-descriptor-is-null", null, LocaleContextHolder.getLocale()));
            return;
        }
        instanceReportCheckInfo.setFacilityCategory(requestParam.get(DatabaseUtils.getFieldName(FinanceReportResponseDataVo::getFacilityCategory)).toString());
        instanceReportCheckInfo.setFacilityDescriptor(requestParam.get(DatabaseUtils.getFieldName(FinanceReportResponseDataVo::getFacilityDescriptor)).toString());
        instanceReportCheckInfo.setCheckResult(true);
        instanceReportCheckInfo.setRequestParam(requestParam);
    }

    private Object getSourceValue(PropertyInfo sourceProperty, InstanceInfoExtend instanceInfoExtend) throws Exception {
        String fieldName = sourceProperty.getId();
        Object fieldValue = getFieldValueByFieldName(instanceInfoExtend, fieldName);
        if (fieldValue == null) {
            fieldValue = instanceInfoExtend.getData().get(fieldName);
        }
        return fieldValue;
    }

    public Object getFieldValueByFieldName(Object object, String fieldName) throws IllegalAccessException {
        Class<?> clazz = object.getClass();
        List<Field> fields = getAllFields(clazz);
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.getName().equals(fieldName)) {
                return field.get(object);
            }
        }
        return null;
    }

    private static List<Field> getAllFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()));
        // 获取父类的字段
        if (clazz.getSuperclass() != null) {
            fields.addAll(getAllFields(clazz.getSuperclass()));
        }
        return fields;
    }

    private boolean checkByTargetConstraint(Object sourceValue, FinanceReportDictionaryInfo targetProperty, InstanceReportCheckInfo instanceReportCheckInfo) {
        switch (targetProperty.getConstraint()) {
            case M -> {
                // 非空型
                if (sourceValue == null) {
                    instanceReportCheckInfo.setCheckResult(false);
                    instanceReportCheckInfo.setCheckMessage(messageSource.getMessage("property-value-validate-fail", new Object[]{targetProperty.getFieldName()}, LocaleContextHolder.getLocale()));
                    return false;
                }
                return true;
            }
            case C -> {
                return true;
            }
            case O -> {
                return true;
            }
        }
        return false;
    }

    private FinanceReportMappingRuleInfo getMappingRuleByModel(List<FinanceReportMappingRuleInfo> mappingRuleInfos, String modelId, String groupId) {
        for (FinanceReportMappingRuleInfo financeReportMappingRuleInfo : mappingRuleInfos) {
            if (financeReportMappingRuleInfo.getModelGroupIdList() != null && financeReportMappingRuleInfo.getModelGroupIdList().contains(groupId)) {
                return financeReportMappingRuleInfo;
            } else if (financeReportMappingRuleInfo.getModelIdList() != null && financeReportMappingRuleInfo.getModelIdList().contains(modelId)) {
                return financeReportMappingRuleInfo;
            }
        }
        return null;
    }

    @Override
    protected FinanceReportMappingRuleInfo genObject() {
        return new FinanceReportMappingRuleInfo();
    }

    private List<ModelInfo> getAllModelInfos(List<String> groupIdList) throws Exception {
        ModelSearchParam modelSearchParam = new ModelSearchParam();
        modelSearchParam.addSubCondition(CMDBTool.getFieldName(ModelInfo::getGroupPath)
                , new SubCondition(CriteriaOpsType.in.name(), groupIdList));
        CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        return modelService.doSelectShowNormalModelByPath(modelSearchParam);
    }

    private List<ModelInfo> getAllModelInfos(List<String> groupIdList, List<String> modelIdList) throws Exception {
        CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        return modelService.selectByGroupPathIdsOrModelIds(groupIdList, modelIdList);
    }

    @Override
    public Object getFinanceReportHistoryInfoByPage(SearchParam param) throws Exception {
        param.setSearchClass(FinanceReportHistoryInfo.class);
        Criteria criteria = genCriteria(param);
        if (StringUtils.isEmpty(param.getSortName())) {
            // 默认按照上报事件倒序排列
            param.setSortName(DatabaseUtils.getFieldName(FinanceReportHistoryInfo::getReportDate));
            param.setSortOrder("DESC");
        }
        // 设置引擎类型名称及引擎名称
        List<FinanceReportHistoryInfo> resultList = CMDBTool.selectPageList(financeReportHistoryInfoMapper, criteria, param);
        ViewConvertContext context = new ViewConvertContext();
        return viewManager.getListViewObject(resultList, FinanceReportHistoryInfo.class, param, context);
    }
}
